namespace FSharpChess
open System
open System.Windows.Forms
open System.Drawing
module main =
    //do Application.EnableVisualStyles()
    [<STAThread>]
    let mutable m_squareFrom = -1
    let mutable m_movesPossible = new System.Collections.Generic.List<Move>()
    let mutable m_blnInMouseDown = false
    let mutable m_curPieceCursor = null
    let mutable m_squareTo = -1
    let mutable mvsinlvw = 0
    let form=
        let temp=new SharpChess.frmMain()
        let MoveNow() =
            if  Funcs2.IsThinking(Funcs.gm.PlayerToPlay) && (not Funcs2.IsPondering) then
                Funcs.ForceImmediateMove(Funcs.gm.PlayerToPlay)
        let RenderStatus(msg) =
            if msg<>"" then
                temp.anltextBox.Text <- temp.anltextBox.Text + msg + Environment.NewLine 
                else temp.anltextBox.Text <- ""
        let INTELLEGENCE_HUMAN = 0
        let INTELLEGENCE_COMPUTER = 1
        let SetFormState() =
            temp.mnuNew.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.mnuOpen.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.mnuSave.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.mnuUndoMove.Enabled <- ((not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering) && Funcs.gm.Mhst.Count > 0)
            temp.mnuRedoMove.Enabled <- ((not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering) && Funcs.MoveRedoList.Count > 0)
            temp.mnuUndoAllMoves.Enabled <- temp.mnuUndoMove.Enabled
            temp.mnuRedoAllMoves.Enabled <- temp.mnuRedoMove.Enabled
            temp.mnuPasteFEN.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.mnuThink.Enabled <- ((not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering) && Funcs.CanMove(Funcs.gm.PlayerToPlay))
            temp.mnuMoveNow.Enabled <- Funcs2.IsThinking(Funcs.gm.PlayerToPlay) && not Funcs2.IsPondering
            temp.mnuResumePlay.Enabled <- Funcs.IsPaused() && Funcs.CanMove(Funcs.gm.PlayerToPlay)
            temp.mnuPausePlay.Enabled <- not (Funcs.IsPaused())
            temp.mnuDifficulty.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.mnuGame.Enabled <- true
            temp.mnuComputer.Enabled <- true
            temp.mnuShowThinking.Enabled <- true
            temp.tbrNew.Enabled <- temp.mnuNew.Enabled
            temp.tbrOpen.Enabled <- temp.mnuOpen.Enabled
            temp.tbrSave.Enabled <- temp.mnuSave.Enabled
            temp.tbrUndoMove.Enabled <- temp.mnuUndoMove.Enabled
            temp.tbrRedoMove.Enabled <- temp.mnuRedoMove.Enabled
            temp.tbrUndoAllMoves.Enabled <- temp.mnuUndoAllMoves.Enabled
            temp.tbrRedoAllMoves.Enabled <- temp.mnuRedoAllMoves.Enabled
            temp.tbrThink.Enabled <- temp.mnuThink.Enabled
            temp.tbrMoveNow.Enabled <- temp.mnuMoveNow.Enabled
            temp.tbrResumePlay.Enabled <- temp.mnuResumePlay.Enabled
            temp.tbrPausePlay.Enabled <- temp.mnuPausePlay.Enabled
            temp.cboIntellegenceWhite.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            temp.cboIntellegenceBlack.Enabled <- not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay)) || Funcs2.IsPondering
            for picobj in temp.m_picSquares do
                let pic =(picobj :?> PictureBox)
                pic.Enabled <- Funcs.CanMove(Funcs.gm.PlayerToPlay) 
            temp.cboIntellegenceWhite.SelectedIndex <- if Attack.PlayerWhite.Intellegence=Human then INTELLEGENCE_HUMAN else INTELLEGENCE_COMPUTER
            temp.cboIntellegenceBlack.SelectedIndex <- if Attack.PlayerBlack.Intellegence=Human then INTELLEGENCE_HUMAN else INTELLEGENCE_COMPUTER

        let HandlePlayer_MoveConsidered(msg) =
            RenderStatus(msg)
        let Player_MoveConsidered(msg:string) =
            if not (Search.gmanals.getimm()) then
                if temp.InvokeRequired then
                    let fd = new Converter<_,_>(fun s -> HandlePlayer_MoveConsidered(s))
                    temp.Invoke(fd,[|box(msg)|]) |> ignore
                else
                    HandlePlayer_MoveConsidered(msg)
        let HandlePlayer_ThinkingBeginning() =
            SetFormState()
        let Player_ThinkingBeginning() =
            if temp.InvokeRequired then
                temp.Invoke(new MethodInvoker(fun() -> HandlePlayer_ThinkingBeginning())) |> ignore
            else
                HandlePlayer_ThinkingBeginning()
        let BOARD_SQUARE_COLOUR_WHITE = System.Drawing.Color.FromArgb(229,197,105)
        let BOARD_SQUARE_COLOUR_BLACK = System.Drawing.Color.FromArgb(189,117,53)
        let SQUARE_BRIGHTNESS = 48
        let BOARD_SQUARE_COLOUR_WHITE_BRIGHT = System.Drawing.Color.FromArgb(Math.Min(229 + SQUARE_BRIGHTNESS,255), Math.Min(197 + SQUARE_BRIGHTNESS,255), Math.Min(105 + SQUARE_BRIGHTNESS,255))
        let BOARD_SQUARE_COLOUR_BLACK_BRIGHT = System.Drawing.Color.FromArgb(Math.Min(189 + SQUARE_BRIGHTNESS,255), Math.Min(117 + SQUARE_BRIGHTNESS,255), Math.Min(53 + SQUARE_BRIGHTNESS,255))
        
        let RenderBoardColours() =
            for i in [0..2..6] do
                for j in [0..2..6] do
                    temp.m_picSquares.[i, j].BackColor <- BOARD_SQUARE_COLOUR_WHITE
                    temp.m_picSquares.[i + 1, j + 1].BackColor <- BOARD_SQUARE_COLOUR_WHITE
                    temp.m_picSquares.[i, j + 1].BackColor <- BOARD_SQUARE_COLOUR_BLACK
                    temp.m_picSquares.[i + 1, j].BackColor <- BOARD_SQUARE_COLOUR_BLACK
            
            // Render selection highlights
            if (m_squareFrom <> -1) then
                for move in m_movesPossible do
                    let picTo = temp.m_picSquares.[Ref.fi.[move.To], Ref.ri.[move.To]]
                    picTo.BackColor <- if picTo.BackColor = BOARD_SQUARE_COLOUR_WHITE then BOARD_SQUARE_COLOUR_WHITE_BRIGHT else BOARD_SQUARE_COLOUR_BLACK_BRIGHT
        let GetPieceImage(pieceid) =
            temp.imgPieces.Images.[UI.imageIndex(Funcs.gm.Pcs.[pieceid].pcIsWhite, Funcs.gm.Pcs.[pieceid].Name)]
        let AddMoveToHistory(move) =
            if Funcs.gm.Pcs.[move.mvPiece].pcIsWhite then
                let lvi = [|(temp.lvwMoveHistory.Items.Count+1).ToString(); Funcs.gm.MhstStr.[Funcs.gm.MhstStr.Count-1] ;""|]
                temp.lvwMoveHistory.Items.Add( new ListViewItem( lvi ) )|>ignore
            else
                let lvi = 
                    if Funcs.gm.MhstStr.Count>1 then
                        [|temp.lvwMoveHistory.Items.Count.ToString(); Funcs.gm.MhstStr.[Funcs.gm.MhstStr.Count-2] ;Funcs.gm.MhstStr.[Funcs.gm.MhstStr.Count-1]|]
                    else
                        [|(temp.lvwMoveHistory.Items.Count+1).ToString(); "" ;Funcs.gm.MhstStr.[Funcs.gm.MhstStr.Count-1]|]
                if temp.lvwMoveHistory.Items.Count > 0 then temp.lvwMoveHistory.Items.RemoveAt(temp.lvwMoveHistory.Items.Count-1)
                temp.lvwMoveHistory.Items.Add( new ListViewItem( lvi ) )|>ignore
            temp.lvwMoveHistory.Items.[temp.lvwMoveHistory.Items.Count-1].EnsureVisible()
            mvsinlvw <- mvsinlvw + 1
        let RemoveLastHistoryItem() =
            temp.lvwMoveHistory.Items.RemoveAt(temp.lvwMoveHistory.Items.Count - 1)
            mvsinlvw <- ((mvsinlvw - 1)/2) * 2
            m_squareFrom <- -1
            m_movesPossible <- new System.Collections.Generic.List<Move>()
        let SyncTree() =
            let rec SyncTreeInner (node:TreeNode) i =
                let mv = Funcs.gm.MhstStr.[i]
                let childs = ResizeArray.ofList  [for tn in node.Nodes -> tn.Text]
                let indx = childs.IndexOf(mv)
                if indx = -1 then () 
                else
                    let newNode = node.Nodes.[indx]
                    newNode.Expand()
                    temp.opntreeView.SelectedNode<-newNode
                    if Funcs.gm.MhstStr.Count>i+1 then SyncTreeInner newNode (i+1)
            let bases = ResizeArray.ofList  [for tn in temp.opntreeView.Nodes -> tn.Text]
            let mv = Funcs.gm.MhstStr.[0]
            let test=bases.[0]
            let indx = bases.IndexOf(mv)
            if indx = -1 then () 
            else
                let newNode = temp.opntreeView.Nodes.[indx]
                temp.opntreeView.SelectedNode<-newNode
                if Funcs.gm.MhstStr.Count>1 then SyncTreeInner newNode 1
        let RenderBoard() =
            RenderBoardColours()
            for i = 0 to Ref.SQUARE_COUNT-1 do
                if Ref.f.[i]<>"-" then
                    let square = Funcs.gm.Sqs.[i]
                    if (square = -1 || i = m_squareFrom) then
                        temp.m_picSquares.[Ref.fi.[i], Ref.ri.[i]].Image <- null
                    else
                        temp.m_picSquares.[Ref.fi.[i], Ref.ri.[i]].Image <- GetPieceImage(square)
                    temp.m_picSquares.[Ref.fi.[i], Ref.ri.[i]].BorderStyle <- System.Windows.Forms.BorderStyle.None
            // Render Last Move highlights
            if (Funcs.gm.Mhst.Count > 0) then
                temp.m_picSquares.[Ref.fi.[Funcs.gm.Mhst.[Funcs.gm.Mhst.Count-1].From], Ref.ri.[Funcs.gm.Mhst.[Funcs.gm.Mhst.Count-1].From]].BorderStyle <- System.Windows.Forms.BorderStyle.Fixed3D
                temp.m_picSquares.[Ref.fi.[Funcs.gm.Mhst.[Funcs.gm.Mhst.Count - 1].To], Ref.ri.[Funcs.gm.Mhst.[Funcs.gm.Mhst.Count-1].To]].BorderStyle <- System.Windows.Forms.BorderStyle.Fixed3D
            // Render player status
            if (Funcs.gm.PlayerToPlay = Attack.PlayerWhite) then
                temp.lblWhiteClock.BorderStyle <- System.Windows.Forms.BorderStyle.FixedSingle
                temp.lblBlackClock.BorderStyle <- System.Windows.Forms.BorderStyle.None
                temp.lblWhiteClock.BackColor <- if Move_gen.IsInCheckMate(Funcs.gm) then Color.Red else (if Attack.is_in_check(Attack.PlayerWhite,Funcs.gm,false) then Color.Orange else Color.LightGray)
                temp.lblBlackClock.BackColor <- Color.FromName(System.Drawing.KnownColor.Control.ToString())
            else
                temp.lblBlackClock.BorderStyle <- System.Windows.Forms.BorderStyle.FixedSingle
                temp.lblWhiteClock.BorderStyle <- System.Windows.Forms.BorderStyle.None
                temp.lblWhiteClock.BackColor <- Color.FromName(System.Drawing.KnownColor.Control.ToString())
                temp.lblBlackClock.BackColor <- if Move_gen.IsInCheckMate(Funcs.gm) then Color.Red else (if Attack.is_in_check(Attack.PlayerBlack,Funcs.gm,false) then Color.Orange else Color.LightGray)
            temp.lblBlackClock.ForeColor <- Color.Black
            temp.lblWhiteClock.ForeColor <- Color.Black
            temp.lblGamePaused.Visible <- false
            // Set form state
            temp.lblWhitePosition.Text <- Eval.PositionPoints(Attack.PlayerWhite,Funcs.gm).ToString()
            temp.lblBlackPosition.Text <- Eval.PositionPoints(Attack.PlayerBlack,Funcs.gm).ToString()
            temp.lblWhitePoints.Text <- Eval.Points(Attack.PlayerWhite,Funcs.gm).ToString()
            temp.lblBlackPoints.Text <- Eval.Points(Attack.PlayerBlack,Funcs.gm).ToString()
            temp.lblWhiteScore.Text <- Eval.Score(Attack.PlayerWhite,Funcs.gm,false,[]).ToString()
            temp.lblBlackScore.Text <- Eval.Score(Attack.PlayerBlack,Funcs.gm,false,[]).ToString()
            // Update move history
            while (Funcs.gm.Mhst.Count<mvsinlvw) do
                RemoveLastHistoryItem()
            while (Funcs.gm.Mhst.Count>mvsinlvw) do
                AddMoveToHistory(Funcs.gm.Mhst.[Funcs.gm.Mhst.Count-1])
            if Opn.inOpening && Funcs.gm.MhstStr.Count>0 then SyncTree()
            SetFormState()
            RenderStatus("")
            temp.Refresh()
        let RenderOpen() = 
            Opn.load()
            for tn in Funcs.OpHashtoTreeView (Opn.psns) do temp.opntreeView.Nodes.Add(tn) |>ignore
        let GetMovesListFromNode() =
            let rec genList ml (cn:TreeNode) =
                if cn <> null then 
                    genList (cn.Text::ml) cn.Parent 
                    else ml
            let curnode = temp.opntreeView.SelectedNode
            let mvlist= genList [] curnode
            Funcs.New("")
            Attack.PlayerWhite.Intellegence <- Human
            Attack.PlayerBlack.Intellegence <- Human
            List.iter Funcs.pgnMakeMove mvlist
        let opntreeView_DoubleClick() =
            GetMovesListFromNode()
        let OpReLoad() =
            temp.opntreeView.Nodes.Clear()
            for tn in Funcs.OpHashtoTreeView (Opn.psns) do temp.opntreeView.Nodes.Add(tn) |>ignore
            if Funcs.gm.MhstStr.Count>0 then SyncTree()
        let addbutton_Click() = 
            Opn.addvrs(Funcs.OpPsnsfromHist(ResizeArray.toList(Funcs.gm.MhstStr)))
            OpReLoad()
        let delbutton_Click() = 
            GetMovesListFromNode()
            let sn = temp.opntreeView.SelectedNode
            let psns = Opn.GetPsnsFromNode sn
            Opn.DeletePsns psns
            OpReLoad()
        let bestbutton_Click() = 
            let sn = temp.opntreeView.SelectedNode
            let tag = sn.Tag.ToString()
            let mv = sn.Text
            Opn.MakeBest(tag,mv)
            OpReLoad()
        let savbutton_Click() = 
            Opn.toFile()
            Opn.toFileTxt()
        let HandleGame_BoardPositionChanged() =
            m_squareFrom <- -1
            m_movesPossible <- new System.Collections.Generic.List<FSharpChess.Move>()
            RenderBoard()
        let Game_BoardPositionChanged() =
            if temp.InvokeRequired then
                temp.Invoke(new MethodInvoker(fun() -> HandleGame_BoardPositionChanged())) |> ignore
            else
                HandleGame_BoardPositionChanged()
        let RenderClocks() =
            temp.lblWhiteClock.Text <- Attack.PlayerWhite.Clock.TimeElapsedDisplay.Hours.ToString().PadLeft(2,'0') + ":" + Attack.PlayerWhite.Clock.TimeElapsedDisplay.Minutes.ToString().PadLeft(2,'0') + ":" + Attack.PlayerWhite.Clock.TimeElapsedDisplay.Seconds.ToString().PadLeft(2,'0')
            temp.lblBlackClock.Text <- Attack.PlayerBlack.Clock.TimeElapsedDisplay.Hours.ToString().PadLeft(2,'0') + ":" + Attack.PlayerBlack.Clock.TimeElapsedDisplay.Minutes.ToString().PadLeft(2,'0') + ":" + Attack.PlayerBlack.Clock.TimeElapsedDisplay.Seconds.ToString().PadLeft(2,'0')
            temp.lblWhiteClock.Refresh()
            temp.lblBlackClock.Refresh()
        let SQUARE_SIZE = 42
        let OrientBoard() =
            for i = 0 to Ref.SQUARE_COUNT-1 do
                if Ref.f.[i]<>"-" then
                    let square = Funcs.gm.Sqs.[i] 
                    let picSquare = temp.m_picSquares.[Ref.fi.[i], Ref.ri.[i]]
                    if (Funcs.Orientation=OriWhite) then
                        picSquare.Left <- Ref.fi.[i]*SQUARE_SIZE + 1
                        picSquare.Top  <- 7*SQUARE_SIZE - Ref.ri.[i]*SQUARE_SIZE + 1
                    else
                        picSquare.Left <- 7*SQUARE_SIZE - Ref.fi.[i]*SQUARE_SIZE + 1
                        picSquare.Top  <- Ref.ri.[i]*SQUARE_SIZE + 1
            // Made the rank and file labels flip also.
            for indCtrl = 0 to temp.pnlMain.Controls.Count-1 do
                // Position each label of coordinates according to the orientation
                let strName = temp.pnlMain.Controls.[indCtrl].Name
                if (strName.StartsWith("lblFile")) then
                     // For the hard-coded constants "lblFile" and "+ 30" see CreateBoard()
                    let iFileSize = System.Convert.ToInt32(strName.Substring(7, strName.Length - 7)) * SQUARE_SIZE
                    temp.pnlMain.Controls.[indCtrl].Left <- (if (Funcs.Orientation = OriWhite) then iFileSize else 7 * SQUARE_SIZE - iFileSize) + 30
                elif (strName.StartsWith("lblRank")) then
                    // For the hard-coded constants "lblRank" and "+ 16" see CreateBoard()
                    let iRankSize = System.Convert.ToInt32(strName.Substring(7, strName.Length - 7)) * SQUARE_SIZE
                    temp.pnlMain.Controls.[indCtrl].Top <- (if (Funcs.Orientation = OriWhite) then 7 * SQUARE_SIZE - iRankSize else iRankSize) + 16
        let StartNormalGame() =
            Funcs.StartNormalGame()
            OrientBoard()
            RenderBoard()
            RenderClocks()
            SetFormState()
            RenderOpen()
            temp.timer.Start()
        let picSquare_MouseDown(s:obj,e:System.Windows.Forms.MouseEventArgs) =
            if (not m_blnInMouseDown) && e.Button = MouseButtons.Left && not (Funcs2.IsThinking(Funcs.gm.PlayerToPlay) && not Funcs2.IsPondering) then
                m_blnInMouseDown <- true
                Funcs.SuspendPondering()
                let picFrom = (s :?> PictureBox)
                let intOrdinalFrom = Convert.ToInt32(picFrom.Tag)
                let squareFrom = FSharpChess.Funcs.gm.Sqs.[intOrdinalFrom]
                let pieceFrom = Funcs.gm.Pcs.[squareFrom]
                if (squareFrom <> -1 && pieceFrom.pcIsWhite = Funcs.gm.PlayerToPlay.prIsWhite) then
                    picFrom.Image <- null
                    picFrom.Refresh()
                    m_curPieceCursor <- temp.m_acurPieceCursors.[UI.imageIndex(pieceFrom.pcIsWhite, pieceFrom.Name)]
                    temp.pnlEdging.Cursor <- m_curPieceCursor
                    // Mark possible moves
                    m_squareFrom <- intOrdinalFrom
                    m_movesPossible <- FSharpChess.Move_gen.GenerateLegalMoves(squareFrom,Funcs.gm)
                    RenderBoardColours()
                    temp.pnlEdging.Refresh()
                    if (picFrom.DoDragDrop(pieceFrom, DragDropEffects.Move) = DragDropEffects.Move ) then
                        let mutable blnMoveMade = false
                        let pieceTo = Funcs.gm.Sqs.[m_squareTo]
                        // Is it an empty space or enemy piece
                        if (pieceTo = -1 || Funcs.gm.Pcs.[pieceTo].pcIsWhite <> Funcs.gm.PlayerToPlay.prIsWhite) then
                            // Check to see it the move is valid, by comparing against all possible valid moves
                            let mutable blnIsPromotion = false
                            let mutable movenamePromotion = NullMove
                            let mutable endfor = false
                            for move in m_movesPossible do
                                if (move.To = m_squareTo && not endfor) then
                                    if (not blnIsPromotion) then
                                        if(move.mvName=PawnPromotionQueen||move.mvName=PawnPromotionRook||move.mvName=PawnPromotionBishop||move.mvName=PawnPromotionKnight) then
                                                blnIsPromotion <- true;
                                                let formPieceSelector = new SharpChess.frmPieceSelector()
                                                formPieceSelector.Colour <- Funcs.gm.Pcs.[move.mvPiece].pcIsWhite
                                                formPieceSelector.ShowDialog(temp)|>ignore
                                                movenamePromotion <- formPieceSelector.MoveNameSelected
                                    if (not blnIsPromotion || move.mvName = movenamePromotion) then
                                        m_squareFrom <- -1
                                        m_movesPossible <- new System.Collections.Generic.List<FSharpChess.Move>()
                                        Funcs.MakeAMove(move)
                                        blnMoveMade <- true
                                        endfor<-true

                        if (not blnMoveMade) then
                            temp.m_picSquares.[Ref.fi.[m_squareFrom], Ref.ri.[m_squareFrom]].Image <- temp.imgPieces.Images.[UI.imageIndex(Funcs.gm.Pcs.[Funcs.gm.Sqs.[m_squareFrom]].pcIsWhite, Funcs.gm.Pcs.[Funcs.gm.Sqs.[m_squareFrom]].Name)]
                            m_squareFrom <- -1 
                            m_movesPossible <- null
                            RenderBoardColours()
                    else
                        temp.m_picSquares.[Ref.fi.[m_squareFrom], Ref.fi.[m_squareFrom]].Image <- temp.imgPieces.Images.[UI.imageIndex(Funcs.gm.Pcs.[Funcs.gm.Sqs.[m_squareFrom]].pcIsWhite, Funcs.gm.Pcs.[Funcs.gm.Sqs.[m_squareFrom]].Name)]
                        m_squareFrom <- -1 
                        m_movesPossible <- null
                        RenderBoardColours()
                        Funcs.ResumePondering()
                    temp.pnlEdging.Cursor <- Cursors.Default
                else
                    FSharpChess.Funcs.ResumePondering()
                m_blnInMouseDown <- false
        let picSquare_DragDrop(sender:obj) =
            m_squareTo <- Convert.ToInt32((sender:?>PictureBox).Tag)
        let picSquare_DragOver(e:DragEventArgs) =
            e.Effect <- DragDropEffects.Move
        let picSquare_GiveFeedback(e:GiveFeedbackEventArgs) =
            if e.UseDefaultCursors then
                e.UseDefaultCursors <- false
            if (temp.pnlEdging.Cursor <> temp.Cursor ) then
                temp.pnlEdging.Cursor <- m_curPieceCursor
        let CreateBoard() =
            for intRank = 0 to 7 do
                let lblRank = new System.Windows.Forms.Label()
                lblRank.BackColor <- System.Drawing.Color.Transparent
                lblRank.Font <- new System.Drawing.Font("Arial", 12.0f, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
                lblRank.Name <- "lblRank" + intRank.ToString()
                lblRank.Size <- new System.Drawing.Size(SQUARE_SIZE/2, SQUARE_SIZE)
                lblRank.TabIndex <- 12
                lblRank.Text <- (intRank+1).ToString()
                lblRank.TextAlign <- System.Drawing.ContentAlignment.MiddleCenter
                lblRank.Left <- 0
                lblRank.Top <- 7*SQUARE_SIZE - intRank*SQUARE_SIZE + 16
                temp.pnlMain.Controls.Add( lblRank )
            for intFile = 0 to 7 do
                let lblFile = new System.Windows.Forms.Label()
                lblFile.BackColor <- System.Drawing.Color.Transparent
                lblFile.Font <- new System.Drawing.Font("Arial", 12.0f, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
                lblFile.Name <- "lblFile" + intFile.ToString()
                lblFile.Size <- new System.Drawing.Size(SQUARE_SIZE, SQUARE_SIZE/2)
                lblFile.TabIndex <- 12
                lblFile.Text <- FSharpChess.Ref.f.[intFile]
                lblFile.TextAlign <- System.Drawing.ContentAlignment.MiddleCenter
                lblFile.Left <- intFile*SQUARE_SIZE + 30
                lblFile.Top <- 8*SQUARE_SIZE + 24
                temp.pnlMain.Controls.Add( lblFile )
            let tmp_picSquares = Array2D.create 8 8 (new PictureBox())
            for f = 0 to 7 do
                for r = 0 to 7 do
                    let picSquare = new System.Windows.Forms.PictureBox()
                    picSquare.Name <- "picSquare" + f.ToString() + r.ToString()
                    picSquare.Size <- new System.Drawing.Size(SQUARE_SIZE, SQUARE_SIZE)
                    picSquare.SizeMode <- System.Windows.Forms.PictureBoxSizeMode.CenterImage
                    picSquare.TabIndex <- 0
                    picSquare.TabStop <- false
                    //need to change if change to 64 board
                    picSquare.Tag <- r*8+f
                    let handler = new MouseEventHandler(fun s e -> picSquare_MouseDown(s,e))
                    picSquare.MouseDown.AddHandler(handler)
                    let handler = new DragEventHandler(fun s _ -> picSquare_DragDrop(s))
                    picSquare.DragDrop.AddHandler(handler)
                    picSquare.DragOver.Add(fun e -> picSquare_DragOver(e))
                    picSquare.GiveFeedback.Add(fun e -> picSquare_GiveFeedback(e))
                    picSquare.AllowDrop <- true
                    temp.pnlEdging.Controls.Add( picSquare )
                    tmp_picSquares.[f,r] <- picSquare
            temp.m_picSquares <- tmp_picSquares

        let formDifficulty = new SharpChess.frmDifficulty()
        let setupformDifficulty =
            let SetGeneralDifficulty() =
                formDifficulty.lblLevel.Text <- formDifficulty.trkLevel.Value.ToString()
                match ((int)formDifficulty.trkLevel.Value) with
                    |1 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(2)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(1)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |2 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(4)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(2)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |3 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(6)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(3)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |4 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(8)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(4)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |5 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(10)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(5)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |6 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(12)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(6)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |7 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(14)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(7)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |8 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(16)
                        formDifficulty.chkRestrictSearchDepth.Checked <- true
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(8)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |9 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(20)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |10 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(30)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |11 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(40)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |12 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(60)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |13 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(120)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |14 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(60)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |15 ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(120)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
                    |_ ->
                        formDifficulty.numMoves.Value <- Convert.ToDecimal(120)
                        formDifficulty.numMinutes.Value <- Convert.ToDecimal(600)
                        formDifficulty.chkRestrictSearchDepth.Checked <- false
                        formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(32)
                        formDifficulty.chkEnablePondering.Checked <- false
            let SetFormState() =
                formDifficulty.grpLevel.Enabled <- formDifficulty.radLevel.Checked
                formDifficulty.grpCustom.Enabled <- formDifficulty.radCustom.Checked
                formDifficulty.trkLevel.Visible <- formDifficulty.grpLevel.Enabled
                formDifficulty.lblLevel.Visible <- formDifficulty.grpLevel.Enabled
                formDifficulty.numMaximumSearchDepth.Enabled <- formDifficulty.chkRestrictSearchDepth.Checked
            let CalculateMoveTimes() =
                formDifficulty.lblAverageSeconds.Text <- Math.Max(Convert.ToInt32(formDifficulty.numMinutes.Value*60.0M / formDifficulty.numMoves.Value), 1).ToString()
                formDifficulty.lblMaximumSeconds.Text <- (Int32.Parse(formDifficulty.lblAverageSeconds.Text)*2).ToString()
                formDifficulty.lblLevel.Text <- formDifficulty.trkLevel.Value.ToString()
            let btnCancel_Click() =
                formDifficulty.Close()
            let btnOK_Click() =
                Funcs.DifficultyLevel <- if formDifficulty.radLevel.Checked then formDifficulty.trkLevel.Value else 0
                Funcs.ClockMoves <- (int)formDifficulty.numMoves.Value
                Funcs.gmtim.ClockTime <- new TimeSpan(0, (int)formDifficulty.numMinutes.Value, 0)
                Funcs.gmtim.ClockIncrementPerMove <- new TimeSpan(0, 0, 0)
                Funcs.gmtim.ClockFixedTimePerMove <- new TimeSpan(0, 0, 0)
                Search.MaximumSearchDepth <- if formDifficulty.chkRestrictSearchDepth.Checked then (int)formDifficulty.numMaximumSearchDepth.Value else 0
                Funcs.EnablePondering <- formDifficulty.chkEnablePondering.Checked
                formDifficulty.Close()
            let frmDifficulty_Load() =
                formDifficulty.radLevel.Checked <- Funcs.DifficultyLevel > 0
                if (formDifficulty.radLevel.Checked) then
                    formDifficulty.trkLevel.Value <- Funcs.DifficultyLevel
                formDifficulty.radCustom.Checked <- Funcs.DifficultyLevel = 0
                formDifficulty.numMoves.Value <- Convert.ToDecimal(Math.Max(Funcs.ClockMoves, 1))
                //formDifficulty.numMinutes.Value <- Convert.ToDecimal(Funcs.GetClockTime())
                formDifficulty.chkRestrictSearchDepth.Checked <- Search.MaximumSearchDepth > 0
                formDifficulty.numMaximumSearchDepth.Value <- Convert.ToDecimal(Math.Max(Search.MaximumSearchDepth,1))
                formDifficulty.chkEnablePondering.Checked <- Funcs.EnablePondering
                SetFormState()
            let trkLevel_Scroll() =
                SetGeneralDifficulty()
            let radLevel_CheckedChanged() =
                SetFormState()
                SetGeneralDifficulty()
            let radCustom_CheckedChanged() =
                SetFormState()
            let chkRestrictSearchDepth_CheckedChanged() =
                SetFormState()
            let numMoves_ValueChanged() =
                CalculateMoveTimes()
            let numMinutes_ValueChanged() =
                CalculateMoveTimes()
            let numMoves_KeyUp() =
                CalculateMoveTimes()
            let numMinutes_KeyUp() =
                CalculateMoveTimes()
            formDifficulty.btnCancel.Click.Add(fun _ -> btnCancel_Click())
            formDifficulty.btnOK.Click.Add(fun _ -> btnOK_Click())
            formDifficulty.Load.Add(fun _ -> frmDifficulty_Load())
            formDifficulty.trkLevel.Scroll.Add(fun _ -> trkLevel_Scroll())
            formDifficulty.radLevel.CheckedChanged.Add(fun _ -> radLevel_CheckedChanged())
            formDifficulty.radCustom.CheckedChanged.Add(fun _ -> radCustom_CheckedChanged())
            formDifficulty.chkRestrictSearchDepth.CheckedChanged.Add(fun _ -> chkRestrictSearchDepth_CheckedChanged())
            formDifficulty.numMoves.ValueChanged.Add(fun _ -> numMoves_ValueChanged())
            formDifficulty.numMinutes.ValueChanged.Add(fun _ -> numMinutes_ValueChanged())
            formDifficulty.numMoves.KeyUp.Add(fun _ -> numMoves_KeyUp())
            formDifficulty.numMinutes.KeyUp.Add(fun _ -> numMinutes_KeyUp())
        let NewGame() =
            formDifficulty.ShowDialog(temp)|>ignore
            Funcs.New("")
        let OpenGame() =
            let openFileDialog = new OpenFileDialog()
            openFileDialog.Title <- "Load a saved chess game" 
            openFileDialog.Filter <- "FEN files (*.FEN)|*.FEN"
            openFileDialog.FilterIndex <- 2
            if(openFileDialog.ShowDialog() = DialogResult.OK) then
                if( openFileDialog.FileName<>"" ) then
                    let strFEN =System.IO.File.ReadAllText(openFileDialog.FileName)
                    try
                        FSharpChess.Funcs.New(strFEN);
                    with
                        | ex -> MessageBox.Show(ex.Message)|>ignore
            OrientBoard()
            SetFormState()
        let SaveGame() =
            let saveFileDialog = new SaveFileDialog()
            saveFileDialog.Filter <- "FEN files (*.FEN)|*.FEN"
            saveFileDialog.FilterIndex <- 2
            saveFileDialog.FileName <- "SavePos.FEN"
            if(saveFileDialog.ShowDialog() = DialogResult.OK) then
                if( saveFileDialog.FileName<> "" ) then
                    System.IO.File.WriteAllText(saveFileDialog.FileName, Funcs.GetBoardPosition())
        let FlipBoard() =
            Funcs.Flip()
            OrientBoard()
        let cboIntellegenceWhite_SelectedIndexChanged() =
            Attack.PlayerWhite.Intellegence <- if temp.cboIntellegenceWhite.SelectedIndex=INTELLEGENCE_HUMAN then Human else Computer
        let cboIntellegenceBlack_SelectedIndexChanged() =
            Attack.PlayerBlack.Intellegence <- if temp.cboIntellegenceBlack.SelectedIndex=INTELLEGENCE_HUMAN then Human else Computer
        let mnuDifficulty_Click() =
            formDifficulty.ShowDialog(temp)|>ignore
            Funcs.SettingsUpdate()
        let AssignMenuChecks() =
            temp.mnuShowThinking.Checked <- Funcs.ShowThinking
            temp.mnuShowOpenings.Checked <- Funcs.ShowOpenings
        let SizeHistoryPane() =
            // The hard-coded constants allow to see the entire last visible row
            temp.lvwMoveHistory.Top <- if Funcs.ShowThinking then temp.lblWhitePosition.Top + temp.lblWhitePosition.Height + 13 else temp.lblWhiteClock.Top + temp.lblWhiteClock.Height + 9
            temp.lvwMoveHistory.Height <- temp.panel1.Bottom - temp.lvwMoveHistory.Top
        let mnuShowThinking_Click() =
            Funcs.ShowThinking <- not Funcs.ShowThinking
            AssignMenuChecks()
            SizeHistoryPane()
        let SizeOpen() = temp.Width <- if Funcs.ShowOpenings then 1000 else 700
        let mnuShowOpenings_Click() =
            Funcs.ShowOpenings <- not Funcs.ShowOpenings
            AssignMenuChecks()
            SizeOpen()
        let mnuExit_Click() =
            temp.Close()
            Application.Exit()
          
        let load =
            Funcs.iEventMC.Add(fun msg -> Player_MoveConsidered(msg))
            Funcs.iEventTh.Add(Player_ThinkingBeginning)
            Funcs.iEventBPC.Add(Game_BoardPositionChanged)
            Funcs.iEventGP.Add(RenderBoard)
            Funcs.iEventGR.Add(RenderBoard)
            temp.mnuMoveNow.Click.Add(fun _ -> MoveNow())
            temp.mnuNew.Click.Add(fun _ -> NewGame())
            temp.mnuOpen.Click.Add(fun _ -> OpenGame())
            temp.mnuSave.Click.Add(fun _ -> SaveGame())
            temp.mnuUndoMove.Click.Add(fun _ -> Funcs.UndoMove())
            temp.mnuRedoMove.Click.Add(fun _ -> Funcs.RedoMove())
            temp.mnuUndoAllMoves.Click.Add(fun _ -> Funcs.UndoAllMoves())
            temp.mnuRedoAllMoves.Click.Add(fun _ -> Funcs.RedoAllMoves())
            temp.mnuThink.Click.Add(fun _ -> Funcs.Think())
            temp.mnuPausePlay.Click.Add(fun _ -> Funcs.PausePlay())
            temp.mnuResumePlay.Click.Add(fun _ -> Funcs.ResumePlay())
            temp.mnuFlipBoard.Click.Add(fun _ -> FlipBoard())
            temp.tbr.ButtonClick.Add(fun e -> 
                    match e.Button.Tag.ToString() with
                        |"MoveNow" -> MoveNow()
                        |"New" -> NewGame()
                        |"Open" -> OpenGame()
                        |"Save" -> SaveGame()
                        |"UndoMove" -> Funcs.UndoMove()
                        |"RedoMove" -> Funcs.RedoMove()
                        |"UndoAllMoves" -> Funcs.UndoAllMoves()
                        |"RedoAllMoves" -> Funcs.RedoAllMoves()
                        |"Think" -> Funcs.Think()
                        |"PausePlay" -> Funcs.PausePlay()
                        |"ResumePlay" -> Funcs.ResumePlay()
                        |"FlipBoard" -> FlipBoard()
                        |_ -> ()
                    )
            temp.timer.Tick.Add(fun _ -> RenderClocks())
            temp.cboIntellegenceWhite.SelectedIndexChanged.Add(fun _ -> cboIntellegenceWhite_SelectedIndexChanged())
            temp.cboIntellegenceBlack.SelectedIndexChanged.Add(fun _ -> cboIntellegenceBlack_SelectedIndexChanged())
            temp.mnuDifficulty.Click.Add(fun _ -> mnuDifficulty_Click())
            temp.mnuShowThinking.Click.Add(fun _ -> mnuShowThinking_Click())
            temp.mnuShowOpenings.Click.Add(fun _ -> mnuShowOpenings_Click())
            temp.mnuExit.Click.Add(fun _ -> mnuExit_Click())
            temp.Closing.Add(fun _ -> Funcs.TerminateGame())
            temp.mnuCopyFEN.Click.Add(fun _ -> UI.mnuCopyFEN_Click())
            temp.mnuPasteFEN.Click.Add(fun _ -> UI.mnuPasteFEN_Click())
            temp.opntreeView.DoubleClick.Add(fun _ -> opntreeView_DoubleClick())
            temp.addbutton.Click.Add(fun _ -> addbutton_Click())
            temp.delbutton.Click.Add(fun _ -> delbutton_Click())
            temp.savbutton.Click.Add(fun _ -> savbutton_Click())
            temp.bestbutton.Click.Add(fun _ -> bestbutton_Click())
            Funcs.CreateBoard()
            Funcs.GameLoadGame()
            temp.LoadCursors()
            CreateBoard()
            temp.Text <- "F#Chess"
            AssignMenuChecks()
            SizeHistoryPane()
            SizeOpen()
            temp.Show()
            StartNormalGame()
        temp
    [<STAThread>]
    do Application.Run(form)